package com.leyou.trade.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.wxpay.sdk.WXPay;
import com.leyou.auth.utils.UserContext;
import com.leyou.common.exception.LyException;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.trade.constants.PayConstants;
import com.leyou.trade.dto.OrderFormDTO;
import com.leyou.trade.dto.PayResultDTO;
import com.leyou.trade.entity.Order;
import com.leyou.trade.entity.OrderDetail;
import com.leyou.trade.entity.OrderLogistics;
import com.leyou.trade.entity.enums.OrderStatus;
import com.leyou.trade.mapper.OrderMapper;
import com.leyou.trade.service.CartService;
import com.leyou.trade.service.OrderDetailService;
import com.leyou.trade.service.OrderLogisticsService;
import com.leyou.trade.service.OrderService;
import com.leyou.trade.utils.PayHelper;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import feign.FeignException;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ORDER_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.EVICT_ORDER_KEY;
import static com.leyou.trade.constants.PayConstants.ORDER_NO_KEY;
import static com.leyou.trade.constants.PayConstants.TOTAL_FEE_KEY;

@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Resource
    private OrderDetailService detailService;
    @Resource
    private OrderLogisticsService orderLogisticsService;
    @Resource
    private CartService cartService;
    @Resource
    private ItemClient itemClient;
    @Resource
    private UserClient userClient;
    @Resource
    private PayHelper payHelper;
    @Resource
    private AmqpTemplate amqpTemplate;






    @GlobalTransactional
    @Override
    public Long createOrder(@Valid OrderFormDTO orderDTO) {
        Order order = new Order();
        //用户id
        Long id = UserContext.getUser().getId();
        order.setUserId(id);
        //金额
        Map<Long, Integer> carts = orderDTO.getCarts();
        if (CollectionUtils.isEmpty(carts))
            throw new LyException(400,"下单失败，请求参数有误");

        ArrayList<Long> idList = new ArrayList<>(carts.keySet());
        List<SkuDTO> skuDTOList = itemClient.querySkuByIds(idList);
        if (CollectionUtils.isEmpty(skuDTOList))
            throw new LyException(400,"下单失败");

        long totalFee = 0;
        for (SkuDTO skuDTO : skuDTOList) {
            Integer num = carts.get(skuDTO.getId());
            totalFee += skuDTO.getPrice() * num;
        }

        order.setTotalFee(totalFee);
        order.setPaymentType(orderDTO.getPaymentType());
        order.setPostFee(0L);
        order.setActualFee(totalFee + order.getPostFee());
        order.setStatus(1);
        boolean success = save(order);
        if (!success)
            throw new LyException(500,"订单创建失败");

        //orderDetail
        ArrayList<OrderDetail> details = new ArrayList<>();
        for (SkuDTO skuDTO : skuDTOList) {
            Integer num = carts.get(skuDTO.getId());
            OrderDetail detail = new OrderDetail();
            detail.setOrderId(order.getOrderId());
            detail.setImage(StringUtils.substringBefore(skuDTO.getImages(),","));
            detail.setNum(num);
            detail.setSkuId(skuDTO.getId());
            detail.setTitle(skuDTO.getTitle());
            detail.setSpec(skuDTO.getSpecialSpec());
            detail.setPrice(skuDTO.getPrice());
            details.add(detail);
        }

        success = detailService.saveBatch(details);
        if (!success)
            throw new LyException(500,"订单创建失败");

        //orderLogistics
        AddressDTO address = userClient.queryAddressById(orderDTO.getAddressId());
        OrderLogistics logistics = address.toEntity(OrderLogistics.class);
        logistics.setOrderId(order.getOrderId());
        success = orderLogisticsService.save(logistics);
        if (!success)
            throw new LyException(500,"订单创建失败");

        //减库存
        try {
            itemClient.deductStock(carts);
        }catch (FeignException.FeignClientException e){
            throw new LyException(e.status(),e.contentUTF8());
        }

        //清空购物车，mongo
        cartService.deleteCartItemByIds(idList);
        //订单加入死信队列
        amqpTemplate.convertAndSend(ORDER_EXCHANGE_NAME,EVICT_ORDER_KEY,order.getOrderId());
        return order.getOrderId();
    }

    @Override
    public String getPayUrl(Long orderId) {
        Order order = getById(orderId);
        if (order == null)
            throw new LyException(400,"订单编号错误，订单不存在！");
        if (order.getStatus() != OrderStatus.INIT.getValue())
            throw new LyException(400,"订单已支付或关闭");
        Long actualFee = order.getActualFee();

        String url = payHelper.getPayUrl(orderId, 1L, PayConstants.ORDER_DESC);

        return url;


    }

    @Transactional
    @Override
    public void handleNotify(Map<String, String> data) {
        payHelper.checkResultCode(data);
        payHelper.checkResponseSignature(data);
        String outTradeNo = data.get(ORDER_NO_KEY);
        String totalFee = data.get(TOTAL_FEE_KEY);
        if (StringUtils.isBlank(outTradeNo) || StringUtils.isBlank(totalFee))
            throw new LyException(400,"响应数据有误，订单金额或编号为空");
        Order order = getById(Long.valueOf(outTradeNo).longValue());
        if (order.getStatus()!=OrderStatus.INIT.getValue())
            return;
        if (Long.valueOf(totalFee).longValue()!=1L)
            throw new LyException(400,"订单金额有误");
        update().set("status",OrderStatus.PAY_UP.getValue())
                .set("pay_time",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
                .eq("order_id",Long.valueOf(outTradeNo))
                .eq("status",OrderStatus.INIT.getValue())
                .update();

        log.info("处理微信支付通知成功！{}",data);
    }

    @Override
    public Integer queryOrderState(Long orderId) {
        Order order = getById(orderId);
        if (order ==null)
            throw new LyException(400,"订单不存在");
        Integer status = order.getStatus();
        return status;
    }

    @Override
    @Transactional
    public void evictOrderIfNecessary(Long orderId) {
        Order order = getById(orderId);
        if (order == null)
            return;
        if (order.getStatus() != OrderStatus.INIT.getValue())
            return;
        boolean boo = update().set("status", OrderStatus.CLOSED.getValue())
                .set("close_time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
                .eq("order_id", orderId)
                .eq("status", OrderStatus.INIT.getValue())
                .update();
        if (!boo)
            return;
        log.info("已关闭超时未支付订单:{}",orderId);
        List<OrderDetail> details = detailService.query().eq("order_id", orderId).list();
        Map<Long, Integer> map = new HashMap<>();
        for (OrderDetail detail : details) {
            map.put(detail.getSkuId(),detail.getNum());
        }
        itemClient.addStock(map);
    }
}